package futbol.tacticas.concursantes.TacticaPringaos;

import futbol.General;
import futbol.tacticas.Comando;
import futbol.tacticas.ComandoGolpearBola;
import futbol.tacticas.ComandoIrA;
import futbol.tacticas.ComandoTiroAPuerta;
import futbol.tacticas.SituacionJugadores;
import futbol.tacticas.concursantes.Tactica;
import java.awt.Color;
import java.awt.Point;
import java.util.Vector;

/**
 *
 * @author Dou
 */
public class TacticaPringaos implements Tactica {

    // Debug
    private boolean log = true;

    // Vector con la fuerza de nuestros jugadores
    private int nFuerza[] = {7, 7, 7, 7, 6, 6, 6, 6, 6, 7, 7};
    // Vector con la fuerza de los jugadores contrarios
    private int nFuerzaEllos[];
    
    // Vector con la posici�n inicial de los jugadores
    private int nValores[][]=
//    {{-140,15}, {-140,-15}, {-60,50}, {-60,-50}, {-80,0}, {0,-30}, {0,30}, {60, 0}, {90, 40}, {90, -40}, {120, 0}};
    {{-140,15}, {-140,-15}, {-60,50}, {-60,-50}, {-80,0}, {0,-30}, {0,30}, {50, -70}, {50, 70}, {90, 40}, {90, -40}};            
    
    private static double CONSTANTE_PASE_SEGURO = 3.0;
    private static double CONSTANTE_PASE_GOL = 2.0;
    private static double CONSTANTE_PASE_DELANTE = 1.0;
    private static double CONSTANTE_PASE_CAMPO_CONTRARIO = 0.5;
    
    private Point [] Ellos; //array con la situacion del contrario    
    private Point [] Nosotros; // array con la situacion de mis jugadores
    private Point Balon; // Posicion anterior del balon
    private Point BalonActual; // Posicion actual del balon
    private boolean primeraIteracion; 
    private double VelocidadBalon; // Velocidad del balon
    private double AnguloBalon; // Angulo del balon
    private double PosicionBalonX; // Punto desde el que se podr� golpear la bola
    private double PosicionBalonY; // Punto desde el que se podr� golpear la bola

    
    private int nIndiceJugadorContrario;
    
    private int []nCubrir;
    private int []nCubiertos;
    
    private Vector<Comando> Comandos;

    public TacticaPringaos() {
        // Inicializamos los contadores
        Comandos = new Vector();
        Ellos = new Point[11];
        nFuerzaEllos = new int[11];
        
        // Inicializamos la fuerza de los jugadores contrarios a cero
        for(int i = 0; i < 11; i++)
            nFuerzaEllos[i] = 0;
        primeraIteracion = true;
        
        
        // El balon inicialmente estara en el centro
        Balon = new Point(0, 0);
        
        nCubrir = new int[11];
        nCubiertos = new int[11];
        for(int i = 0; i < 11; i++) {
            nCubrir[i] = -1;
            nCubiertos[i] = -1;
        }

    }

    public String getNombre() {
        return "Los Pringaos";
    }

    public Color getColor1() {
        return Color.WHITE;
    }

    public Color getColor2() {
        return Color.RED;
    }

    public Color getColorNumero() {
        return Color.BLACK;
    }

    public int getFuerza(int n) {
        return nFuerza[n];
    }
    
    public int getFuerzaEllos(int n) {
        return nFuerzaEllos[n];
    }
    
    public int getVelocidad(int n) {
        return 10 - nFuerza[n];
    }

    public int getVelocidadEllos(int n) {
        return 10 - nFuerzaEllos[n];
    }

    public int getXInicial(int n) {
        return nValores[n][0];
    }

    public int getYInicial(int n) {
        return nValores[n][1];
    }

    public Vector<Comando> getComandos(SituacionJugadores sj) {

        int i, x; // Indice para los bucles
        
        double DistanciaMinima;
        double temp;
        int IndiceJugador;
        
        double nDistanciaPase;
        double nAnguloPase;
        double nVelocidadBalon;
        
        int nTiempoMinimo;
        int nIndiceDefensa;
        int tempTiempo;
        
        int nReceptor;
        
                
        Comandos.clear();
                
        // Calculamos la fuerza de los jugadores contrarios
        if (primeraIteracion) { // Primera iteracion. No puedo calcular la fuerza. 
           Ellos = sj.getContrario(); // Guardo su posicion actual para calcularla en la proxima iteracion
           primeraIteracion = false;
        }
        else {
            CalculaFuerzaJugadoresContrarios(sj.getContrario());
            Ellos = sj.getContrario();
        }
        
        // Guardo la posicion de mis jugadores
        Nosotros = sj.getMisJugadores();
        // Guardo la posicion actual del balon
        BalonActual = sj.getBola();
                
        // Si hubo gol -> reseteamos el vector de marcajes
        if ((BalonActual.getX() == 0) && (BalonActual.getY() == 0)) {
            for(i = 0; i < 11; i++) {
                nCubrir[i] = -1;
                nCubiertos[i] = -1;
            }
        }
        
        // Si el jugador contrario vuelve a su campo -> dejamos de cubrirle
        for(i = 0; i < 11; i++) {
            if (nCubrir[i] != -1) {
                if (Ellos[nCubrir[i]].getX() > 0) {
                    nCubiertos[nCubrir[i]] = -1;
                    nCubrir[i] = -1;
                }
            }
       }
        
        // Calculo velocidad y angulo del balon
        VelocidadBalon = General.getDistancia(Balon.getX(), Balon.getY(), BalonActual.getX(), BalonActual.getY()) - 1;
        AnguloBalon = General.getAngulo(Balon.getX(), Balon.getY(),  BalonActual.getX(), BalonActual.getY());
        
        // Compruebo si podemos golpear la bola o no
        if ((General.getDistancia(Nosotros[sj.getMasCercanoDeBola()].getX(), Nosotros[sj.getMasCercanoDeBola()].getY(), BalonActual.getX(), BalonActual.getY()) <= 10) &&
            (VelocidadBalon <= 15)) {
            
            // Calculamos la posicion de la bola en la siguiente iteracion
            PosicionBalonX = Math.cos(AnguloBalon) * (VelocidadBalon - 1) + BalonActual.getX();
            PosicionBalonY = Math.sin(AnguloBalon) * (VelocidadBalon - 1) + BalonActual.getY();
            //Log("PosicionBalon(" + PosicionBalonX + ", " + PosicionBalonY + ")");            
            
            // Coloco al jugador que golpeara la pelota en la siguiente posicion que ocupara el balon
            Comandos.add(new ComandoIrA(sj.getMasCercanoDeBola(), PosicionBalonX, PosicionBalonY));            

            // Si no podemos chutar a puerta -> buscamos el mejor pase posible
            if (!ChutarAPuerta(sj.getMasCercanoDeBola())) {
                nReceptor = CalculaMejorPase(sj.getMasCercanoDeBola());
                if (nReceptor == sj.getMasCercanoDeBola()) Desmarcar(sj.getMasCercanoDeBola(), nReceptor);
            } else {
                nReceptor = -1;
                // estamos en ataque
                for(i = 0; i < 11; i++) if (i != sj.getMasCercanoDeBola()) Comandos.add(new ComandoIrA(i, nValores[i][0], nValores[i][1]));            
            }            
        } else { // estamos en defensa
            // Comprobamos si algun jugador contrario puede golpear el balon
            nIndiceJugadorContrario = GolpearBalonContrario(BalonActual);
            if (nIndiceJugadorContrario != -1) {
                for(i = 0; i < 11; i++) {
                    // Calcula la distancia de pase a los contrarios
                    if (i != nIndiceJugadorContrario) {
                        if ((Ellos[i].getX() < 0) && (nCubiertos[i] == -1)) { // Esta en mi campo y no esta cubierto
                            nDistanciaPase = General.getDistancia(sj.getBola().getX(), sj.getBola().getY(), Ellos[i].getX(), Ellos[i].getY());
                            nAnguloPase = General.getAngulo(sj.getBola().getX(), sj.getBola().getY(), Ellos[i].getX(), Ellos[i].getY());
                            if (nDistanciaPase > 50) nVelocidadBalon = getFuerzaEllos(nIndiceJugadorContrario) * 3;
                            else nVelocidadBalon = (int) Math.floor(getFuerzaEllos(nIndiceJugadorContrario) * nDistanciaPase * 2 / 100) * 3;
                            PosicionBalonX = Math.cos(nAnguloPase) * CalculaSumatorio(nVelocidadBalon) + sj.getBola().getX();
                            PosicionBalonY = Math.sin(nAnguloPase) * CalculaSumatorio(nVelocidadBalon) + sj.getBola().getY();            
                            nTiempoMinimo = 1000;
                            nIndiceDefensa = -1;
                            for(x = 2; x < 8; x++) {
                                if ((nCubrir[x] == -1) && (nCubrir[x] != i)) {
                                    tempTiempo = TiempoDistancia(General.getDistancia(PosicionBalonX, PosicionBalonY, Nosotros[x].getX(), Nosotros[x].getY()), x, false);
                                    if (tempTiempo < nTiempoMinimo) {
                                        nTiempoMinimo = tempTiempo;
                                        nIndiceDefensa = x;
                                    }
                                }
                            }
                            if (nIndiceDefensa != -1) {
                                nCubrir[nIndiceDefensa] = i;
                                nCubiertos[i] = nIndiceDefensa;
                                Comandos.add(new ComandoIrA(nIndiceDefensa, PosicionBalonX, PosicionBalonY));
                            }                           
                        }
                    }
                }
            } else {
                // Colocamos a los jugadores en sus posiciones iniciales
                // Al jugador mas proximo a la primera posicion de golpeo de la bola -> le mandamos a esa posicion
                // Calculamos la posicion desde la cual podremos golpear la bola
                PosicionBalonX = Math.cos(AnguloBalon) * CalculaSumatorio(VelocidadBalon) + sj.getBola().getX();
                PosicionBalonY = Math.sin(AnguloBalon) * CalculaSumatorio(VelocidadBalon) + sj.getBola().getY();            
                DistanciaMinima = 1000;
                IndiceJugador = sj.getMasCercanoDeBola();
                
                for(i = 0; i < 11; i++) {
                    if ((nCubrir[i] == -1) || (sj.estoyMasCercaDeBola()))
                        Comandos.add(new ComandoIrA(i, nValores[i][0], nValores[i][1]));
                    else
                        Comandos.add(new ComandoIrA(i, Ellos[nCubrir[i]].getX(), Ellos[nCubrir[i]].getY()));
                    //}
                    temp = General.getDistancia(Nosotros[i].getX(), Nosotros[i].getY(), PosicionBalonX, PosicionBalonY);
                    if (temp < DistanciaMinima) {
                        DistanciaMinima = temp;
                        IndiceJugador = i;
                    }
                }
                
                // Al jugador mas cercano al balon le mandamos a por el
                Comandos.add(new ComandoIrA(IndiceJugador, PosicionBalonX, PosicionBalonY));
            }
        }
        
        // Actualizamos la posicion del balon
        Balon = sj.getBola();
            
    	return Comandos;
    }
    
    // Comprobamos si algun jugador contrario puede golpear el balon
    public int GolpearBalonContrario(Point nBola) {
        int nGolpear = -1;
        
        for(int i = 0; i < 11; i++) 
            if (General.getDistancia(nBola.getX(), nBola.getY(), Ellos[i].getX(), Ellos[i].getY()) < 10) { 
                nGolpear = i;
                break;
            }
    
        return nGolpear;
    }
    
    // Calcula la fuerza de los jugadores contrarios
    public void CalculaFuerzaJugadoresContrarios(Point[] PosicionJugadores) {      
        // Recorremos el array y calculamos la fuerza de cada jugador
        for(int i = 0; i < 11; i++) {
            if (nFuerzaEllos[i] == 0) { // Si a�n no calculamos su fuerza
                // La fuerza la calculamos restando de 10 la distancia recorrida por el jugador entre las dos ultimas iteraciones
                nFuerzaEllos[i] = 10 - (int)General.getDistancia(Ellos[i].getX(), Ellos[i].getY(), PosicionJugadores[i].getX(), PosicionJugadores[i].getY());
                //Log("Jugador: " + i + " - Fuerza: " + nFuerzaEllos[i]);
            }
        }
    }
    
    // Movemos los jugadores para que se desmarquen del contrario
    public void Desmarcar(int nPasador, int nReceptor) {
        int i;
        
        for(i = 2; i < 11; i++) {
            if ((i != nPasador) && (i != nReceptor)) {
                Comandos.add(new ComandoIrA(i, Nosotros[i].getX() + getVelocidad(i), Nosotros[i].getY()));
            }
        }
    }
    
    // Calcula el mejor punto de pase posible
    public int CalculaMejorPase(int nPasador) {
        int i;
        double[] nValoracionPase = new double[11];
        boolean[] nPase_Seguro = new boolean[11];
        boolean[] nPaseDelante = new boolean[11];
        double nPuntuacionMaxima = 0.0;
        int nMejorPase = 0;
        
        for(i = 0; i < 11; i++){
            nValoracionPase[i] = 0.0;
            nPase_Seguro[i] = false;
            nPaseDelante[i] = false;

            if (i == nPasador) continue;
            
            if (PaseSeguro(nPasador, i)) {
                nValoracionPase[i] += CONSTANTE_PASE_SEGURO;
                nPase_Seguro[i] = true;
            }
            
            if (PaseDeGol(i)) {
                nValoracionPase[i] += CONSTANTE_PASE_GOL;
            }
            
            if (PaseDelante(nPasador, i)) {
                nValoracionPase[i] += CONSTANTE_PASE_DELANTE;
                nPaseDelante[i] = true;
            }
            
            if (PaseCampoContrario(i)) {
                nValoracionPase[i] += CONSTANTE_PASE_CAMPO_CONTRARIO;
            }
                
            if (nValoracionPase[i] > nPuntuacionMaxima) {
                nPuntuacionMaxima = nValoracionPase[i];
                nMejorPase = i;
            }
        }
                
        if ((!nPase_Seguro[nMejorPase]) && (Nosotros[nPasador].getX() > -20) && (Nosotros[nPasador].getX() < 20)) {
            nMejorPase = nPasador;
            Comandos.add(new ComandoGolpearBola(nPasador, Nosotros[nPasador].getX() + getVelocidad(nPasador), Nosotros[nPasador].getY()));
        } else {
            Comandos.add(new ComandoGolpearBola(nPasador, Nosotros[nMejorPase].getX(), Nosotros[nMejorPase].getY()));                    
        }
        
        return nMejorPase;
    }
    
    // Comprobamos si la posicion de pase es buena para marcar gol
    public boolean PaseDeGol(int nReceptor) {
        if (General.getDistancia(Nosotros[nReceptor].getX(), Nosotros[nReceptor].getY(), 160, 0) < CalculaSumatorio(getFuerza(nReceptor) * 3)) return true;
        else return false;
    }
    
    // Comprobamos si el pase es hacia delante
    public boolean PaseDelante(int nPasador, int nReceptor) {
        if (Nosotros[nReceptor].getX() < Nosotros[nPasador].getX()) return false;
        else return true;
    }
    
    // Comprobamos si el pase acaba en el campo contrario
    public boolean PaseCampoContrario(int nReceptor) {
        if (Nosotros[nReceptor].getX() > 0) return true;
        else return false;
    }
    
    // Comprobamos si el pase lo puede interceptar algun rival
    public boolean PaseSeguro(int nPasador, int nReceptor) {
        boolean EsPaseSeguro = true;
        int i;
        double nDistanciaPase;
        int nVelocidadBalon;
        int nIteraciones;
        int nIteracionGolpearBalon;        
        Point nPosicionBalonFinal;
        Point nPosicionBalonGolpeo;
        int temp;
        
        nDistanciaPase = General.getDistancia(Nosotros[nPasador].getX(), Nosotros[nPasador].getY(), Nosotros[nReceptor].getX(), Nosotros[nReceptor].getY());
        // Velocidad que tendra el balon cuando lo golpee el pasador
        if (nDistanciaPase > 50) nVelocidadBalon = getFuerza(nPasador) * 3;
        else nVelocidadBalon = (int) Math.floor(getFuerza(nPasador) * nDistanciaPase * 2 / 100) * 3;
        
        // Calculamos el numero de iteraciones que tardara el balon en llegar al receptor
        nIteraciones = 1;
        // Calculamos el numero de iteraciones necesarias hasta que el receptor pueda golpear el balon
        nIteracionGolpearBalon = 0;
        temp = nVelocidadBalon;
        for(i = (int) Math.floor(nDistanciaPase); i >= 10; i -= nVelocidadBalon) {
            if (nVelocidadBalon == 0) { // El pase no llegara a su destino -> esta demasiado lejos para la fuerza del jugador
                break;
            }
            if (nVelocidadBalon <= 15) { // En esta iteracion ya se puede golpear el balon
                if (nIteracionGolpearBalon == 0) nIteracionGolpearBalon = nIteraciones;
            }
            nVelocidadBalon--;
            nIteraciones++;
        }
        
        nVelocidadBalon = temp;
        nPosicionBalonGolpeo = PosicionBalon(nIteracionGolpearBalon, BalonActual, Nosotros[nReceptor], nVelocidadBalon);
        nPosicionBalonFinal = PosicionBalon(nIteraciones, BalonActual, Nosotros[nReceptor], nVelocidadBalon);
        for(i = 0; i < 11; i++) {
            // Si el rival esta detras del pasador -> no podra interceptar el balon
            if (Ellos[i].getX() < Nosotros[nPasador].getX()) continue;
            
            // Comprobamos si el rival podra llegar al balon
            if ((General.getDistancia(Ellos[i].getX(), Ellos[i].getY(), nPosicionBalonGolpeo.getX(), nPosicionBalonGolpeo.getY()) < (10 + DistanciaRecorrer(nIteracionGolpearBalon, i, true))) ||
                (General.getDistancia(Ellos[i].getX(), Ellos[i].getY(), nPosicionBalonFinal.getX(), nPosicionBalonFinal.getY()) < (10 + DistanciaRecorrer(nIteraciones, i, true)))) {
                EsPaseSeguro = false;
                break;
            }
        }
        
        return EsPaseSeguro;
    }
    
    // Calculamos la posicion futura del balon
    public Point PosicionBalon(int nTiempo, Point nPosicionInicial, Point nPosicionFinal, int nVelocidadBalon) {
        Point nPosicion = new Point((int)nPosicionInicial.getX(), (int)nPosicionFinal.getY());
        int i;
        double nAnguloBalon = General.getAngulo(nPosicionInicial.getX(), nPosicionInicial.getY(), nPosicionFinal.getX(), nPosicionFinal.getY());
        
        for(i = 1; i <= nTiempo; i++) {          
            nPosicion.x += (int)(Math.cos(nAnguloBalon) * (nVelocidadBalon - i));
            nPosicion.y += (int)(Math.sin(nAnguloBalon) * (nVelocidadBalon - i));
        }
        
        return nPosicion;
    }
    
    // Devuelve la distancia que puede recorrer un jugador en un determinado intervalo de tiempo
    public int DistanciaRecorrer(int nTiempo, int nJugador, boolean nRival) {
        if (nRival) return getVelocidadEllos(nJugador) * nTiempo;
        else return getVelocidad(nJugador) * nTiempo;
    }
    
    // Devueve el numero de iteraciones que le llevara a un jugador recorrer determinada distancia
    public int TiempoDistancia(double nDistancia, int nJugador, boolean nRival) {
        if (nRival) return (int) Math.ceil(nDistancia / getVelocidadEllos(nJugador));
        else return (int) Math.ceil(nDistancia / getVelocidad(nJugador));
    }
    
        
    // Calculamos la distancia que recorrera el balon antes de que le podamos golpear
    public int CalculaSumatorio(double n) {
        int distancia;
        double x;
        
        distancia = 0;
        for(x = n; x >= 15; x--) distancia += x;
        
        if (distancia == 0) distancia = (int)n;
        
        return distancia;
    }
    
    // Chutamos a puerta
    public boolean ChutarAPuerta(int n) {
        int nDistancia = (int) General.getDistancia(Nosotros[n].getX(), Nosotros[n].getY(), 160, 0);

        // Comprobamos si el jugador esta cerca de la porteria contraria y tiene posibilidades de marcar gol
        if (nDistancia < CalculaSumatorio(getFuerza(n) * 3))   {             
            Comandos.add(new ComandoTiroAPuerta(n, 0));
            return true;
        }
        return false;
    }
    
    public void Log(String cadena) {
    	if (log) {
    		System.out.println(cadena);
    	}
    }

}

